<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Flip</title>
</head>

<body>
  <h1>FLIP 动画</h1>
  <p>Fist, Last, Invert, Play</p>
  <p>参考 <a
      href="https://codesandbox.io/s/my-vue-w0u5j?file=/src/App.vue">https://codesandbox.io/s/my-vue-w0u5j?file=/src/App.vue</a>
  </p>
  <div class="container">
    <li class="item" data-id="1">1</li>
  </div>

  <button onclick="reform()">Reform</button>

  <script>
    const dom = {
      container: document.querySelector('.container'),
      list: document.querySelectorAll('li.item')
    }
    const source = [];
    const size = 120;
    for (let i = 0; i < size; i++) {
      source.push(i + 1);
    }

    paint(source)

    function paint(arr) {
      dom.container.innerHTML = arr.reduce((a, id) => {
        return a + `<li class="item" data-id="${id}"> ${id} </li>`
      }, '');
    }

    function collect() {
      return source.map(id => {
        const li = document.querySelector(`li.item[data-id="${id}"]`)
        const rect = li.getBoundingClientRect()
        const { top, left } = rect
        return [left, top]
      })
    }

    function invert(first, last) {
      return source.map((id, i) => {
        const [left, top] = first[i];
        const [newLeft, newTop] = last[i];
        return [left - newLeft, top - newTop];
      })
    }

    function play(inversion) {
      source.forEach((id, i) => {
        const li = document.querySelector(`li.item[data-id="${id}"]`)
        li.style.transition = 'none'
        li.style.transform = `translate(${inversion[i].map(s => s + 'px')})`

        li.clientWidth
        li.style.transition = '1s linear'
        li.style.transform = `translate(0, 0)`
      })
    }

    function reform() {
      const first = collect()                 // F
      const newList = shuffle(source);
      paint(newList)
      const last = collect()                  // L
      const inversion = invert(first, last)   // I
      play(inversion);                        // P
    }

    function shuffle(arr) {
      const cp = arr.slice()
      const res = [];
      while (cp.length)
        res.push(pick(cp));
      return res;
    }
    function pick(arr) {
      const index = rand(arr.length)
      return arr.splice(index, 1)[0]
    }
    function rand(a, b) {
      if (b == undefined) {
        b = a; a = 0;
      }
      return Math.floor(Math.random() * (b - a)) + a;
    }
  </script>

  <style>
    .container {
      border: 1px saddlebrown solid;
      padding: 4px;
      display: flex;
      flex-wrap: wrap;
      justify-content: center;
      align-items: center;
    }

    li.item {
      font-size: 24px;
      line-height: 72px;
      width: 72px;
      height: 72px;
      margin: 4px;
      background-color: tomato;
      list-style: none;
      text-align: center;
    }
  </style>
</body>

</html>